#include "watchpoint.h"
#include "expr.h"

#define NR_WP 32     
#define NR_WWP 32  

static WP wp_pool[NR_WP];
static WP *head, *free_;
static WP weakwp_pool[NR_WWP];
extern char *regfile[];


void init_wp_pool() {
	int i;
	for(i = 0; i < NR_WP - 1; i ++) {
		wp_pool[i].NO = i;
		wp_pool[i].next = &wp_pool[i + 1];
	}

	wp_pool[NR_WP - 1].NO = NR_WP - 1;
	wp_pool[NR_WP - 1].next = NULL;

	head = NULL;
	free_ = wp_pool;

	for(i = 0; i < NR_WWP; i ++) {
		weakwp_pool[i].NO = i;    //same as regno
		weakwp_pool[i].next = NULL;
		strcpy(weakwp_pool[i].expr,regfile[i]);
		
		weakwp_pool[i].val = 0;
	}


}

WP* new_wp()    // free link -> h link 
{
	WP* hp, *fp;
	hp=head; fp=free_;
	if(free_->next!=NULL) {   //pick one from front
		free_=free_->next;
	}
	else {
		printf("No more room for wp\n");
		assert(0);
	}
	if(hp==NULL){        //insert into end
		hp=fp;
		head=hp;
	}else{
		while(hp->next!=NULL){
			hp=hp->next;
		}
		hp->next=fp; 
	}
	fp -> next = NULL;
	return fp;
}

void free_wp(WP* wp)    //head link -> free link
{
	WP* hp,*fp;
	hp=head; fp=free_;
	if(hp==NULL){assert(0);}
	if(head->NO==wp->NO){
		head=head->next;
	}
	else {
		while(hp->next!=NULL&&hp->next->NO!=wp->NO){hp=hp->next;}
		if(hp->next->NO==wp->NO){hp->next=hp->next->next;}
		else{assert(0);}
	}

	wp -> next = NULL;

	if(fp==NULL)    //insert into end 
    {
        free_=wp;
        fp=free_;

    }else{
        while(fp->next!=NULL){fp=fp->next;}
        fp->next=wp;
    }

	wp->next=NULL;
}

bool check_wp()    
{
	WP* hp;
	hp=head;
	bool success;
	bool outcome=true;   //means assume the value of all WP keep original value 
	while(hp!=NULL){
		uint32_t now_value = expr(hp->expr,&success);
		if(!success){assert(1);}
		if(now_value!=hp->val)
		{
			outcome=false;  //one change then stop
			printf("Watchpoint %d:%s's value change from %d to %d \n",(hp->NO)+1,hp->expr,hp->val,now_value);
			hp->val=now_value;
			//shouldn't break because all the WP need update
		}
		hp=hp->next;
	}
	return outcome;
}

bool weakcheck_wp(uint32_t pc)    
{
	int i = 0;
	bool success = false;
	bool outcome = true;
	for(i = 0;i < NR_WWP; i ++ ){
		uint32_t now_value = expr(weakwp_pool[i].expr,&success);
		if(!success){assert(1);}
		if(now_value!=weakwp_pool[i].val)
		{
			char trace_buf[128];
			outcome=false;  //one change then stop
			reg_record (trace_buf,pc,weakwp_pool[i].NO,now_value);
			Trace_write("%s\n", trace_buf);
			weakwp_pool[i].val=now_value;
			//shouldn't break because all the WP need update
		}
	}
	return outcome;
}


void delete_wp(int no)
{
	WP* hp;
	hp=&wp_pool[no-1];     //user's WP start from 1 in fact
	free_wp(hp);
	printf("Watchpoint %d successfully removed\n", no);
}

void info_wp()
{
	WP* hp;
	hp=head;
	while(hp!=NULL)
	{
		printf("Watchpoint %d: %s = %d \n",(hp->NO)+1,hp->expr,hp->val);
		hp=hp->next;
	}
}

/* TODO: Implement the functionality of watchpoint */


